package com.mydemo.springlearning.functions.JUC.async;

import lombok.SneakyThrows;

import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;

public class CompletableDemo {
    @SneakyThrows
    public static void main(String[] args) {
//        func1();
        System.out.println("======================分隔符==========================");
//        func2();
        System.out.println("======================分隔符==========================");
//        func3();
        System.out.println("======================分隔符==========================");
        func4();

    }

    /**
     * <h1>结果消费</h1>
     * thenAccept
     * 观察该系列函数的参数类型可知，它们是函数式接口Consumer，这个接口只有输入，没有返回值。
     * thenAcceptBoth
     * thenAcceptBoth函数的作用是，当两个CompletionStage都正常完成计算的时候，就会执行提供的action消费两个异步的结果
     */
    @SneakyThrows
    private static void func4() {
        CompletableFuture<Void> future = CompletableFuture
                .supplyAsync(() -> {
                    int number = new Random().nextInt(10);
                    System.out.println("第一次运算：" + number);
                    return number;
                })
                //此处只能无返回值
                .thenAccept(
                        number -> System.out.println("第二次运算(*5)：" + number * 5)
                );
        future.get();
        System.out.println("======================分隔符==========================");
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int number = new Random().nextInt(3) + 1;
                try {
                    TimeUnit.SECONDS.sleep(number);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任务1结果：" + number);
                return number;
            }
        });

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int number = new Random().nextInt(3) + 1;
                try {
                    TimeUnit.SECONDS.sleep(number);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任务2结果：" + number);
                return number;
            }
        });

        future1.thenAcceptBoth(future2, new BiConsumer<Integer, Integer>() {
            @Override
            public void accept(Integer x, Integer y) {
                System.out.println("最终结果：" + (x + y));
            }
        });

    }

    /**
     * <h1>结果转换</h1>
     * <b>thenApply</b><p>
     * thenApply接收一个函数作为参数，<p>使用该函数处理上一个CompletableFuture调用的结果，<p>
     * 并返回一个具有处理结果的Future对象。<p>
     * <b>thenCompose</b><p>
     * thenCompose的参数为一个返回CompletableFuture实例的函数，<p>
     * 该函数的参数是先前计算步骤的结果。<p>
     * <b>difference</b><p>
     * thenApply转换的是泛型中的类型，返回的是同一个CompletableFuture；
     * thenCompose将内部的CompletableFuture调用展开来并使用上一个CompletableFutre调用的结果在下一步的CompletableFuture调用中进行运算，是生成一个新的CompletableFuture。
     */
    @SneakyThrows
    private static void func3() {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int result = 100;
            System.out.println("第一次运算：" + result);
            return result;
        }).thenApply(number -> {
            int result = number * 3;
            System.out.println("第二次运算 (* 3) ：" + result);
            return result;
        });
        System.out.println("get():" + future.get());
        System.out.println("======================分隔符==========================");
        CompletableFuture<Integer> future2 = CompletableFuture
                .supplyAsync(new Supplier<Integer>() {
                    @Override
                    public Integer get() {
                        int number = new Random().nextInt(30);
                        System.out.println("第一次运算：" + number);
                        return number;
                    }
                })
                .thenCompose(new Function<Integer, CompletionStage<Integer>>() {
                    @Override
                    public CompletionStage<Integer> apply(Integer param) {
                        return CompletableFuture.supplyAsync(new Supplier<Integer>() {
                            @Override
                            public Integer get() {
                                int number = param * 2;
                                System.out.println("第二次运算(*2)：" + number);
                                return number;
                            }
                        });
                    }
                });
        System.out.println("get()2:" + future2.get());

    }

    @SneakyThrows
    private static void func2() {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 如果随机数是偶数则执行算数异常
            if (new Random().nextInt(10) % 2 == 0) {
                int i = 12 / 0;
            }
            System.out.println("finish:顺利执行结束！");
            return "顺利执行——>没有异常";
        });
        // 任务<u>完成</u>或<u>异常</u>方法完成时执行该方法
        // 如果出现了异常,任务结果 runResult 为 null, action 不为 null
        future.whenComplete(new BiConsumer<String, Throwable>() {
            @Override
            public void accept(String runResult, Throwable action) {
                System.out.println("\ncomplete:执行结果：" + runResult + ", 异常信息:" + action);
            }
        });
        // 出现异常时先执行该方法
        future.exceptionally(new Function<Throwable, String>() {
            @Override
            public String apply(Throwable t) {
                System.out.println("exception:异常发生！");
                return "异常信息:" + t.getMessage();
            }
        });
        //通过get()执行方法
        System.out.println("\nget:" + future.get());

    }

    private static void func1() throws InterruptedException, ExecutionException {
        Runnable runnable = () -> System.out.println("无返回结果异步任务");
        CompletableFuture.runAsync(runnable);

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("有返回值的异步任务");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Hello World";
        });
        String result = future.get();
        System.out.println(result);
    }


}
